P3830 [SHOI2012]随机树
题解
题意
解法
首先解决第一个问题,叶节点平均深度的期望值,可以设fi表示有i个叶子节点的随机树的平均深度的期望值,可以得到转移方程为
fi=ifi−1×(i−1)−fi−1+(fi−1+1)×2
其实就是计算当前有i个叶子节点时在i−1个叶子节点的情况下,展开一个节点,计算其深度的影响,化简后也就是
fi=fi−1+i2
然后第二个问题就麻烦了,树深度的期望值,首先根据期望的线性性有
E(x)=i=1∑+∞P(i≤x)
然后可以设fi,j为有i个叶子节点且深度大于等于j的树的出现概率,得出转移方程为
fi,j=k=1∑i−1i−1fk,j−1+fi−k,j−1−fk,j−1×fi−k,j−1
首先k时枚举的左子树中叶子节点的数量,然后求左子树中深度大于等于j−1 的概率,由于左右子树深度都大于j−1的情况在fk,j−1和fi−k,j−1中都统计过,所以要去减去重复的部分,对于除以i−1的部分可以去看这个证明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <bits/stdc++.h>
using namespace std;
const int N = 110;
int n, q;
namespace SubTask1 { double f[N];
void getans() { for(int i = 2; i <= n; i++) f[i] = f[i - 1] + 2.0 / i; printf("%.6lf", f[n]); } }
namespace SubTask2 { double f[N][N];
void getans() { for(int i = 1; i <= n; i++) f[i][0] = 1; for(int i = 2; i <= n; i++) { for(int j = 1; j < i; j++) { for(int k = 1; k < i; k++) f[i][j] += f[k][j - 1] + f[i - k][j - 1] - f[k][j - 1] * f[i - k][j - 1]; f[i][j] /= (i - 1) * 1.0; } } double ans = 0; for(int i = 1; i < n; i++) ans += f[n][i]; printf("%.6lf", ans); } }
int main() { scanf("%d%d", &q, &n); if(q == 1)SubTask1::getans(); if(q == 2)SubTask2::getans(); return 0; }
|